package com.litaomn.fang.hotload.server;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.os.IBinder;
import android.os.ICustomService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;

import com.google.common.collect.Maps;
import com.litaomn.fang.hotload.util.LogUtil;
import com.tencent.mm.fang.FangBridge;
import com.tencent.mm.fang.FangHelpers;
import com.tencent.mm.fang.XC_MethodHook;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.List;
import java.util.Map;

public class CustomService extends ICustomService.Stub {
    private final static String SERVICE_NAME = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? "user.xpservice" :
            "xpservice";
    private final static String AMS_CLASS = "com.android.server.am.ActivityManagerService";
    private final static String SYM_CLASS = "android.os.ServiceManager";

    private static CustomService mCustomService;

    private static ICustomService mClient;

    private static Map<String, Object> mMap;

    public static ICustomService getClient() {
        if (mClient == null) {

            Class<?> ServiceManager = null;
            try {
                ServiceManager = Class.forName("android.os.ServiceManager");
                Method getService = ServiceManager.getDeclaredMethod("getService", String.class);
                mClient = ICustomService.Stub.asInterface((IBinder) getService.invoke(null, SERVICE_NAME));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        return mClient;
    }


    public static void register(final ClassLoader classLoader) {
        Class<?> ActivityManagerService = FangHelpers.findClass(AMS_CLASS, classLoader);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            FangBridge.hookAllConstructors(ActivityManagerService, new XC_MethodHook() {
                @Override
                protected void am(MethodHookParam param) throws Throwable {
                    addService(classLoader);
                }
            });
        } else {
            FangBridge.hookAllMethods(ActivityManagerService, "main", new XC_MethodHook() {
                @Override
                protected void am(XC_MethodHook.MethodHookParam param) throws Throwable {
                    addService(classLoader);
                }
            });
        }

        FangBridge.hookAllMethods(ActivityManagerService, "systemReady", new XC_MethodHook() {
            @Override
            protected void am(MethodHookParam param) throws Throwable {
                mCustomService.systemReady();
            }
        });
    }

    private static void addService(ClassLoader classLoader) {
        mCustomService = new CustomService();

        Class<?> ServiceManager = FangHelpers.findClass(SYM_CLASS, classLoader);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            FangHelpers.csm(ServiceManager, "addService", SERVICE_NAME, mCustomService, true);
        } else {
            FangHelpers.csm(ServiceManager, "addService", SERVICE_NAME, mCustomService);
        }
    }

    private void systemReady() {
        LogUtil.error("systemReady");
        mMap = Maps.newConcurrentMap();
        //keepNetWork();
    }

   /* private void keepNetWork() {

        Class<?> ServiceManager = null;
        try {
            ServiceManager = Class.forName("android.os.ServiceManager");
            Method getService = ServiceManager.getDeclaredMethod("getService", String.class);
            mClient = ICustomService.Stub.asInterface((IBinder) getService.invoke(null, SERVICE_NAME));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }*/
    /*private void initServer() {
        final WebSocket webSocket = new WebSocket(URI.create("ws://192.168.0.163:9002"));
        try {
            webSocket.connectBlocking(5000, TimeUnit.MILLISECONDS);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        webSocket.send(DateFormatUtils.format(System.currentTimeMillis(),
                                DateFormatUtils.ISO_8601_EXTENDED_TIME_FORMAT.getPattern()) + ":alive");
                        SystemClock.sleep(5000);
                    }
                }
            }).start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }*/


    @Override
    public void putString(String key, String value) throws RemoteException {
        mMap.put(key, value);
    }

    @Override
    public void putBoolean(String key, boolean value) throws RemoteException {
        mMap.put(key, value);
    }

    @Override
    public void putInt(String key, int value) throws RemoteException {
        mMap.put(key, value);
    }

    @Override
    public void pugLong(String key, long value) throws RemoteException {
        mMap.put(key, value);
    }

    @Override
    public void putDouble(String key, double value) throws RemoteException {
        mMap.put(key, value);
    }

    @Override
    public void putStringList(String key, List<String> list) throws RemoteException {
        mMap.put(key, list);
    }

    @Override
    public void putStringMap(String key, Map map) throws RemoteException {
        mMap.put(key, map);
    }

    @Override
    public String getString(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (String) value;
    }

    @Override
    public boolean getBoolean(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (boolean) value;
    }

    @Override
    public int getInt(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (int) value;
    }

    @Override
    public long getLong(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (long) value;
    }

    @Override
    public double getDouble(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (double) value;
    }

    @Override
    public List<String> getStringList(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (List<String>) value;
    }

    @Override
    public Map getStringMap(String key) throws RemoteException {
        Object value = mMap.get(key);
        return value == null ? null : (Map) value;
    }

    @Override
    public void execCommond(String commondType, Map map) throws RemoteException {
        switch (commondType) {
            case "connect":
                WebSocketManager.getInstance().connect(map);
                break;
            case "reConnect":
                break;
            case "disConnect":
                break;
            case "send":
                WebSocketManager.getInstance().send();
                break;
        }
    }
}
